/**
 * ...
 * @author Krzysztof Rozalski
 */

package hapi.sprite;

import flash.events.Event;
import flash.Lib;
import haxe.FastList;

class FramesSetAnimation implements FramesSet {

	static var initialized:Bool = false;
	static var anims:FastList<FramesSetAnimation> = new FastList<FramesSetAnimation>();
	static var NEXT_ID:Int = 0;
	
	var startFrame:Int;
	var endFrame:Int;
	var loops:Int;
	var frames:FramesSet;
	var loopsLeft:Int;
	var nextUpdateStamp:Int;
	var id:Int;
	
	public var isPlaying(default, null):Bool;
	public var totalFrames(default, null):Int;
	public var currentFrame:Int;
	public var duration(default, null):Float;
	public var millisPerFrame(default, null):Int;
	public var onComplete:FramesSetAnimation->Void;
	
	public function new(frames:FramesSet, millisPerFrame:Int, startFrame:Int, endFrame:Int, ?loops:Int = -1) {
		this.frames = frames;
		this.startFrame = startFrame;
		this.endFrame = endFrame;
		this.millisPerFrame = millisPerFrame;
		this.loopsLeft = this.loops = loops;
		this.totalFrames = (endFrame - startFrame)+1;
		this.duration = totalFrames * millisPerFrame/1000;
		this.currentFrame = startFrame;
		this.isPlaying = false;
		if (!initialized) {
			flash.Lib.current.stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			initialized = true;
		}
		this.nextUpdateStamp = Lib.getTimer();
		this.id = NEXT_ID++;
		anims.add(this);
	}
	
	static function onEnterFrame(event:Event) {
		updateAnimations();
	}
	
	public static inline function updateAnimations():Void {
		var now:Int = Lib.getTimer();
		for ( a in anims ) 
			if(a.isPlaying) a.update(now);
	}
	
	public static function skipEventRegistering() {
		initialized = true;
	}
	
	public function play() {
		isPlaying = true;
	}
	
	public function stop() {
		isPlaying = false;
	}
	
	public function reset() {
		this.loopsLeft = loops;
		this.currentFrame = startFrame;
	}
	
	public function goto(frame:Int) {
		if (frame <= totalFrames && frame >= 1 ) {
			currentFrame = frame;
			render();
		}
	}
	
	public inline function nextFrame() {
		currentFrame++;
		if (currentFrame > endFrame) loop(); 
		else render();
	}
	
	public inline function prevFrame() {
		currentFrame--;
		if (currentFrame < startFrame) currentFrame = startFrame;
		render();
	}
	
	inline function render() {
		frames.goto(currentFrame);
	}
	
	function loop() {
		if (loopsLeft != 0) {
			--loopsLeft;
			currentFrame = startFrame;
			render();
		}else {
			currentFrame = endFrame;
			stop();
			render();
			if (onComplete != null) onComplete(this);
		}
	}
	
	inline function update(now:Int) {
		if (nextUpdateStamp < now) {
			nextFrame();
			nextUpdateStamp = now + millisPerFrame;
		}
	}
	
	public function toString():String {
		return "FrameSetAnimation(" + id + ")";
	}
}